﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Aeon.Emulator.Sound.FM.Operators
{
    internal static class AdsrConstants
    {
        private const double TenPercentDecibels = -10.0;
        private const double NinetyPercentDecibels = -0.45757490560675125409944193489769;
        public const double ExpRangeDecibels = NinetyPercentDecibels - TenPercentDecibels;
        public const double TenPercentLinear = 3.3219280948873623478703194294894;
        public const double NinetyPercentLinear = 1.5200309344504998496284154159376;
        public const double ExpRangeLinear = NinetyPercentLinear - TenPercentLinear;
        public const double SampleAttackFactor = -2.4150374992788438185462610560522;

        public static readonly double[,] AttackTimes;
        public static readonly double[,] DecayReleaseTimes;
        public static readonly double[,] AttenuationScaleFactors =
        {
            { 0, 0, 0, 0, 0, 0, 0, 0 },
            { 0, 0, 0, 0, 0, -3, -6, -9 },
            { 0, 0, 0, 0, -3, -6, -9, -12 },
            { 0, 0, 0, -1.875, -4.875, -7.875, -10.875, -13.875 },
            { 0, 0, 0, -3, -6, -9, -12, -15 },
            { 0, 0, -1.125, -4.125, -7.125, -10.125, -13.125, -16.125 }, 
            { 0, 0, -1.875, -4.875, -7.875, -10.875, -13.875, -16.875 },
            { 0, 0, -2.625, -5.625, -8.625, -11.625, -14.625, -17.625 },
            { 0, 0, -3, -6, -9, -12, -15, -18 },
            { 0, -0.75, -3.75, -6.75, -9.75, -12.75, -15.75, -18.75 },
            { 0, -1.125, -4.125, -7.125, -10.125, -13.125, -16.125, -19.125 },
            { 0, -1.5, -4.5, -7.5, -10.5, -13.5, -16.5, -19.5 },
            { 0, -1.875, -4.875, -7.875, -10.875, -13.875, -16.875, -19.875 },
            { 0, -2.25, -5.25, -8.25, -11.25, -14.25, -17.25, -20.25 },
            { 0, -2.625, -5.625, -8.625, -11.625, -14.625, -17.625, -20.625 },
            { 0, -3, -6, -9, -12, -15, -18, -21 }
        };

        static AdsrConstants()
        {
            var decayRelease = new double[64, 2];
            var attack = new double[64, 2];

            for(int i = 0; i < 4; i++)
            {
                decayRelease[i, 0] = double.PositiveInfinity;
                decayRelease[i, 1] = double.PositiveInfinity;
                attack[i, 0] = double.PositiveInfinity;
                attack[i, 1] = double.PositiveInfinity;
            }

            for(int i = 4; i < 60; i++)
            {
                var factor = Math.Exp(-0.173 * i);

                decayRelease[i, 0] = 45211 * factor;
                decayRelease[i, 1] = 9439.3 * factor;

                attack[i, 0] = 3195.7 * factor;
                attack[i, 0] = 1688.1 * factor;
            }

            for(int i = 60; i < 64; i++)
            {
                decayRelease[i, 0] = 2.4;
                decayRelease[i, 1] = 0.51;
                attack[i, 0] = 0;
                attack[i, 1] = 0;
            }

            DecayReleaseTimes = decayRelease;
            AttackTimes = attack;
        }
    }
}
